import 'dart:math';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../resources/kq_theme_colors.dart';
import 'base/kq_chart_method.dart';
import 'base/kq_chart_model.dart';
import 'kq_chart_line_model.dart';
import 'package:path_drawing/path_drawing.dart';

class KqChartLine extends StatefulWidget {
  ///内部参数设置
  final ChartLineModel chartModel;

  ///控住多图刷新的key，同一页面有多个图是必填
  final String? keyTag;

  ///背景色
  final Color? backGroundColor;

  ///总高度
  final double? height;

  ///总宽度
  final double? width;

  final List<List<ChartLineValue>>? valueList;

  const KqChartLine(
      {Key? key,
      required this.chartModel,
      this.keyTag,
      this.height,
      this.width,
      this.valueList,
      this.backGroundColor})
      : super(key: key);

  @override
  State<KqChartLine> createState() => _KqChartLineState();
}

class _KqChartLineState extends State<KqChartLine>
    with SingleTickerProviderStateMixin {
  late Animation<double> animation;
  late AnimationController controller;
  late ChartLineModel lineModel;

  @override
  void initState() {
    super.initState();
    lineModel = Get.put(widget.chartModel, tag: widget.keyTag);
    lineModel.setValueList(widget.valueList ?? widget.chartModel.chartArray,
        widget.chartModel.chartModel);
    controller = AnimationController(
      duration: lineModel.chartModel.duration,
      vsync: this,
    );
    animation = Tween(begin: 0.0, end: 1.0).animate(controller)
      ..addListener(() {
        lineModel.chartModel.animationTime = animation.value;
        lineModel.update();
      })
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          lineModel.chartModel.isAnimationEnd = true;
          lineModel.update();
        }
      });
    //启动动画(正向执行)
  }

  @override
  dispose() {
    //路由销毁时需要释放动画资源
    controller.dispose();
    super.dispose();
  }

  KqLineChartPainter getLineChart() {
    KqChartModel model = lineModel.chartModel;
    KqLineChartPainter painter = KqLineChartPainter(
        yStyle: TextStyle(fontSize: model.yFont, color: model.yColor),
        xStyle: TextStyle(fontSize: model.xFont, color: model.xColor),
        chartModel: model,
        maxY: lineModel.maxHeight,
        lines: lineModel.chartArray,
        xList: lineModel.xList,
        xValue: lineModel.xValue,
        yList: lineModel.yList,
        yValue: lineModel.yValue,
        avgYPointList: lineModel.avgYPointList,
        shaderColors: lineModel.shaderColors,
        crossShowList: lineModel.crossShowList,
        lineColors: lineModel.lineColors);
    return painter;
  }

  @override
  Widget build(BuildContext context) {
    lineModel.chartModel.isAnimationEnd = false;
    lineModel.chartModel.animationTime = 0;
    controller.forward(from: 0);
    lineModel.setValueList(widget.valueList ?? widget.chartModel.chartArray,
        widget.chartModel.chartModel);
    KqChartModel item = lineModel.chartModel;
    return Container(
      width: widget.width,
      height: widget.height,
      color: widget.backGroundColor,
      child: RepaintBoundary(
          child: Stack(
        children: [
          GetBuilder<ChartLineModel>(
            init: lineModel,
            tag: widget.keyTag,
            builder: (controller) => CustomPaint(
              size: Size(item.sizeWidth, item.sizeHeight),
              foregroundPainter:
                  widget.backGroundColor != null ? getLineChart() : null,
              painter: widget.backGroundColor == null ? getLineChart() : null,
              child: widget.backGroundColor != null
                  ? Container(
                      alignment: Alignment.center,
                      width: item.sizeWidth,
                      height: item.sizeWidth,
                    )
                  : null,
            ),
          ),
          Padding(
            padding: EdgeInsets.only(
                left: item.xLeft!,
                top: item.yTop!,
                right: item.xRight!,
                bottom: item.yBottom!),
            child: SizedBox(
              width: lineModel.xWidth,
              height: lineModel.yHeight,
              child: GestureDetector(
                onPanDown: (details) {
                  if (!item.isShowValue) {
                    if (item.isShowClickValue) {
                      for (List<ChartLineValue> list in lineModel.chartArray) {
                        for (ChartLineValue info in list) {
                          double x = info.xPoint - item.xLeft!;
                          double y = info.yPoint - item.yTop!;
                          if ((x - 10 < details.localPosition.dx &&
                                  x + 10 > details.localPosition.dx) &&
                              (y - 10 < details.localPosition.dy &&
                                  y + 10 > details.localPosition.dy)) {
                            info.isShow = true;
                          } else {
                            info.isShow = false;
                          }
                        }
                      }
                    }
                    lineModel.update();
                  }
                },
                onPanUpdate: (details) {
                  if (!item.isShowValue) {
                    if (item.isShowSlideValue) {
                      for (List<ChartLineValue> list in lineModel.chartArray) {
                        for (ChartLineValue info in list) {
                          double x = info.xPoint - item.xLeft!;
                          if (x - 10 < details.localPosition.dx &&
                              x + 10 > details.localPosition.dx) {
                            info.isShow = true;
                          } else {
                            info.isShow = false;
                          }
                        }
                      }
                    }
                    lineModel.update();
                  }
                },
                onPanEnd: (DragEndDetails e) {
                  // if (!lineModel.isShowValue) {
                  //   lineModel.update();
                  // }
                },
              ),
            ),
          )
          // GestureDetector(),
        ],
      )),
    );
  }
}

//
class KqLineChartPainter extends CustomPainter {
  ///基本数据
  final KqChartModel chartModel;

  ///Y轴文案样式
  final TextStyle yStyle;

  ///X轴文案样式
  final TextStyle xStyle;

  ///x轴坐标数组
  final List xList;

  ///y轴坐标数组
  final List yList;

  ///横坐标内容
  List xValue;

  ///纵坐标内容
  List yValue;

  ///平均线坐标
  List<double> avgYPointList;

  final List<Color>? lineColors;

  ///遮罩颜色数组与chartLineArray一一对应，在ChartBarValue中barColor为null时使用
  final List<List<Color>>? shaderColors;

  ///最大值
  final double maxY;

  ///具体数据
  final List<List<ChartLineValue>> lines;

  ///横坐标显示内容个数不为0时，使用传入需要显示内容点的对应下标
  List<int> crossShowList;

  List<LineCanvasModel> lineModels = [];

  KqLineChartPainter({
    Key? key,
    required this.chartModel,
    required this.lineColors,
    required this.shaderColors,
    required this.yStyle,
    required this.xStyle,
    required this.maxY,
    required this.xList,
    required this.yList,
    required this.xValue,
    required this.yValue,
    required this.lines,
    required this.avgYPointList,
    required this.crossShowList,
  }) : super();

  @override
  void paint(Canvas canvas, Size size) {
    var paint = Paint()
      ..strokeWidth = 1
      ..style = PaintingStyle.stroke;
    KqChartMethod.drawXYAxisPath(
        canvas: canvas,
        paint: paint,
        axisColor: chartModel.axisColor!,
        xList: xList,
        yList: yList,
        xRight: chartModel.xRight!,
        isDivide: chartModel.isDivide,
        dividerColor: chartModel.dividerColor!,
        hintLineSolid: chartModel.hintLineSolid,
        crossShowList: crossShowList,
        yStyle: yStyle,
        xStyle: xStyle,
        yValue: yValue,
        xValue: xValue,
        yAisTop: chartModel.yAxisTop!,
        initialPointX: chartModel.initialPointX,
        unit: chartModel.unit);
    _initPath(canvas, paint);
    KqChartMethod.drawAvgLine(
        canvas: canvas,
        paint: paint,
        avgYPointList: avgYPointList,
        isAvg: chartModel.isAvg,
        xList: xList,
        xRight: chartModel.xRight!,
        avgColors: chartModel.avgColors,
        avgValues: chartModel.avgValues ?? [],
        hintAvgLineSolid: chartModel.hintAvgLineSolid,
        initialPointX: chartModel.initialPointX,
        isAvgValue: chartModel.isAvgValue);
  }

  //计算path
  void _initPath(Canvas canvas, Paint xyPaint) {
    for (int i = 0; i < lines.length; i++) {
      List<ChartLineValue> points = lines[i];
      Path path = Path();
      if (points.isNotEmpty) {
        if (chartModel.isCurve) {
          path = KqChartMethod.getSmoothLinePath(points);
        } else {
          path.moveTo(points[0].xPoint, points[0].yPoint);
          for (int j = 1; j < points.length; j++) {
            ChartLineValue point = points[j];
            path.lineTo(point.xPoint, point.yPoint);
          }
        }
        List paths = KqChartMethod.getAnimationLinePath(path, points, xList,
            yList, chartModel.animationTime, chartModel.isAnimationEnd);
        Path shadowPath = paths[1];
        lineModels.add(LineCanvasModel(
          path: paths.first,
          points: paths.last,
          shadowPaths: shadowPath,
          lineColor:
              lineColors == null ? KqThemeColors.textLightBlue : lineColors![i],
          lineWidth: points.first.lineWidth,
          shaderColors: shaderColors == null
              ? [
                  const Color(0x8740A9FF),
                  const Color(0x0040A9FF),
                ]
              : shaderColors![i],
        ));
      }
    }
    _drawLine(canvas);
  }

  ///绘制曲线或者折线以及文案
  void _drawLine(Canvas canvas) {
    if (lineModels.isNotEmpty) {
      for (int i = 0; i < lineModels.length; i++) {
        LineCanvasModel model = lineModels[i];
        if (lines[i].length > 1) {
          _drawLineNormal(canvas, model, i);
        } else {
          _drawOnlyPoint(canvas, model, i);
        }
      }
    }
  }

  ///绘制单个点
  _drawOnlyPoint(Canvas canvas, LineCanvasModel model, int i) {
    if (chartModel.isAddMask) {
      Rect shadowRect =
          Rect.fromLTRB(xList.first, yList.first, xList.last, yList.last);
      var shader = LinearGradient(
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter,
              tileMode: TileMode.clamp,
              colors: model.shaderColors)
          .createShader(shadowRect);
      Path path = Path();
      path.moveTo(lines[i].first.xPoint - 2, yList.last);
      path.lineTo(lines[i].first.xPoint - 2, lines[i].first.yPoint);
      path.lineTo(lines[i].first.xPoint + 2, lines[i].first.yPoint);
      path.lineTo(lines[i].first.xPoint + 2, yList.last);
      path.lineTo(lines[i].first.xPoint - 2, yList.last);
      path.close();
      canvas.drawPath(
          path,
          Paint()
            ..shader = shader
            ..isAntiAlias = true
            ..style = PaintingStyle.fill);
    }
    canvas.drawCircle(
        Offset(lines[i].first.xPoint, lines[i].first.yPoint),
        chartModel.pointRadius!,
        Paint()
          ..isAntiAlias = true
          ..strokeCap = StrokeCap.round
          ..color = model.lineColor
          ..strokeWidth = 1
          ..style = PaintingStyle.fill);
  }

  ///绘制正常曲线折线
  void _drawLineNormal(Canvas canvas, LineCanvasModel model, int i) {
    if (chartModel.isAddMask) {
      Rect shadowRect =
          Rect.fromLTRB(xList.first, yList.first, xList.last, yList.last);
      var shader = LinearGradient(
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter,
              tileMode: TileMode.clamp,
              colors: model.shaderColors)
          .createShader(shadowRect);
      canvas.drawPath(
          model.shadowPaths,
          Paint()
            ..shader = shader
            ..isAntiAlias = true
            ..style = PaintingStyle.fill);
    }
    canvas.drawPath(
        model.path,
        Paint()
          ..strokeWidth = model.lineWidth
          ..color = model.lineColor
          ..style = PaintingStyle.stroke);
    List<ChartLineValue> info = lines[i];
    for (int n = 0; n < model.points; n++) {
      if (info.length > n) {
        ChartLineValue value = info[n];
        if (chartModel.isShowPoint) {
          canvas.drawCircle(
              Offset(value.xPoint, value.yPoint),
              chartModel.pointRadius!,
              Paint()
                ..isAntiAlias = true
                ..strokeCap = StrokeCap.round
                ..color = model.lineColor
                ..strokeWidth = 1
                ..style = PaintingStyle.fill);
        }
        if (chartModel.isShowValue) {
          var textValue = TextPainter(
              textAlign: TextAlign.center,
              ellipsis: '.',
              maxLines: 1,
              text: TextSpan(text: value.yValue, style: value.style),
              textDirection: TextDirection.rtl)
            ..layout();
          textValue.paint(
              canvas,
              Offset(value.xPoint - textValue.width / 2,
                  value.yPoint - textValue.height - 6));
        } else {
          if (value.isShow) {
            var textValue = TextPainter(
                textAlign: TextAlign.center,
                ellipsis: '.',
                maxLines: 1,
                text: TextSpan(text: value.yValue, style: value.style),
                textDirection: TextDirection.rtl)
              ..layout();
            textValue.paint(
                canvas,
                Offset(value.xPoint - textValue.width / 2,
                    value.yPoint - textValue.height - 6));
            if (info.first.isCountDivider) {
              var paint = Paint()
                ..strokeWidth = 1
                ..style = PaintingStyle.stroke
                ..color = info.first.dividerColor;
              Path horizontalPath = Path();
              horizontalPath.moveTo(value.xPoint, yList.last);
              horizontalPath.lineTo(value.xPoint, value.yPoint);
              if (chartModel.hintLineSolid) {
                canvas.drawPath(horizontalPath, paint);
              } else {
                canvas.drawPath(
                  dashPath(
                    horizontalPath,
                    dashArray: CircularIntervalList<double>(<double>[4.0, 2.0]),
                  ),
                  paint,
                );
              }
              Path verticalPath = Path();
              verticalPath.moveTo(
                  xList.first - chartModel.initialPointX, value.yPoint);
              verticalPath.lineTo(value.xPoint, value.yPoint);
              if (chartModel.hintLineSolid) {
                canvas.drawPath(verticalPath, paint);
              } else {
                canvas.drawPath(
                  dashPath(
                    verticalPath,
                    dashArray: CircularIntervalList<double>(<double>[4.0, 2.0]),
                  ),
                  paint,
                );
              }
            }
          }
        }
      }
    }
  }

  @override
  bool shouldRepaint(covariant KqLineChartPainter oldDelegate) {
    return true;
  }
}

//绘制图表的计算之后的结果模型集
class LineCanvasModel {
  ///遮罩层路径
  Path shadowPaths;

  ///折线或曲线路径
  Path path;

  ///点的数组
  // List<Offset> points;
  int points;

  ///遮罩层颜色
  List<Color> shaderColors;

  ///线的颜色
  Color lineColor;

  double lineWidth;

  LineCanvasModel({
    required this.points,
    required this.shadowPaths,
    required this.shaderColors,
    required this.lineColor,
    required this.path,
    required this.lineWidth,
  });
}
